window.onload = function () {
    const ENTER_KEY_CODE = 13;
    const ALL_ENV = 0;
    const ACTIVE_ENV = 1;
    const COMPLETE_ENV = 2;
    const COMPLETE_STATUS = 1;
    const ACTIVE_STATUS = 0;
    const SUCCESS = 'success';
    const HOST = 'http://127.0.0.1';
    const PORT = '8080';

    let msgDiv = $('#msg_div');
    let todoInput = $('#todo_input');
    let todoTable = $('#todo_table');

    let allBtn = $('#all_btn');
    let activeBtn = $('#active_btn');
    let completeBtn = $('#complete_btn');
    let clearCompleteBtn = $('#clear_complete_btn');

    let leftItemsSpan = $('#left_items_span');

    let leftItemsCount = 0;
    let todoListLocal = [];
    let currentEnv = ALL_ENV;

    getTodoItemsFromServer();

    todoInput.keydown(function () {
        if (event.which === ENTER_KEY_CODE) {
            event.preventDefault();
            let content = todoInput.val().trim();
            if (content !== '') {
                todoInput.val('');

                let id = new Date().getTime();
                if (currentEnv !== COMPLETE_ENV) {
                    addTodoToTable(id, content, ACTIVE_STATUS);
                }
                increaseLeftItem();
                addTodoToServer(id, content, ACTIVE_STATUS);
                addTodoToLocal(id, content, ACTIVE_STATUS);
            }
        }
    });

    allBtn.click(function () {
        currentEnv = ALL_ENV;
        resetTable(todoListLocal);
        updateEnvButton();
    });

    activeBtn.click(function () {
        currentEnv = ACTIVE_ENV;
        resetTable(getActiveItems(todoListLocal));
        updateEnvButton();

    });

    completeBtn.click(function () {
        currentEnv = COMPLETE_ENV;
        resetTable(getCompleteItems(todoListLocal));
        updateEnvButton();
    });

    function updateEnvButton() {
        if (currentEnv === ALL_ENV) {
            allBtn.attr('class', 'btn btn-flat chosen');
            activeBtn.attr('class', 'btn btn-flat unchosen');
            completeBtn.attr('class', 'btn btn-flat unchosen');
        } else if (currentEnv === ACTIVE_ENV) {
            allBtn.attr('class', 'btn btn-flat unchosen');
            activeBtn.attr('class', 'btn btn-flat chosen');
            completeBtn.attr('class', 'btn btn-flat unchosen');
        } else {
            allBtn.attr('class', 'btn btn-flat unchosen');
            activeBtn.attr('class', 'btn btn-flat unchosen');
            completeBtn.attr('class', 'btn btn-flat chosen');
        }
    }

    clearCompleteBtn.click(function () {
        resetTable(getActiveItems(todoListLocal));

        let completeItems = getCompleteItems(todoListLocal);
        delCompleteItemsServer(completeItems);
        delCompleteItemsLocal(completeItems);
        updateCompleteBtn();
        updateEnvButton();
    });

    function delCompleteItemsLocal(completeItems) {
        for (let item of completeItems) {
            todoListLocal.splice(todoListLocal.indexOf(item), 1);
        }
    }

    function getActiveItems(todoList) {
        return todoList.filter(item => item.status === ACTIVE_STATUS);
    }

    function initView() {
        resetTable(todoListLocal);
        updateCompleteBtn();
        leftItemsCount = getActiveItems(todoListLocal).length;
        leftItemsSpan.text(`Left items: ${leftItemsCount}`);
    }

    function createTodoDom(latestId, content, status) {
        let logo = status === 0 ? 'radio_button_unchecked' : 'radio_button_checked';
        let pClass = status === 0 ? 'text-justify' : 'text-justify complete';
        return '<tr id="' + latestId.toString() + '_tr">' +
            '<th scope="row"><i id="' + latestId.toString() + '_i" class="material-icons my-text-red">' + logo + '</i></th>' +
            '<td class="todo_item">' +
            '<p id="' + latestId.toString() + '_p" class="' + pClass + '">' +
            content +
            '</p>' +
            '</td>' +
            '<td class="close_icon">' +
            '<button id="' + latestId.toString() + '_del_btn" type="button" class="close" aria-label="Close">' +
            '<span aria-hidden="true">&times;</span>' +
            '</button>' +
            '</td>' +
            '</tr>';
    }

    function isComplete(id) {
        let todo = getItemFromTodoList(id);
        return todo.status === COMPLETE_STATUS;
    }

    function getCompleteItems(todoList) {
        return todoList.filter(item => item.status === COMPLETE_STATUS);
    }

    function increaseLeftItem() {
        leftItemsSpan.text(`Left items: ${++leftItemsCount}`);
    }

    function addTodoToLocal(id, content, status) {
        let todo = {'id': id, 'content': content, 'status': status};
        todoListLocal.push(todo);
    }

    function decreaseLeftItems() {
        leftItemsSpan.text(`Left items: ${--leftItemsCount}`);
    }

    function complete(id) {
        if (currentEnv === ACTIVE_ENV) {
            $('#' + id + '_tr').remove();
        } else {
            let pId = `${id.toString()}_p`;
            let iId = `${id.toString()}_i`;

            $('#' + pId).addClass('complete');
            $('#' + iId).text('radio_button_checked');
        }

        decreaseLeftItems();
        updateStatus(id);
    }

    function active(id) {
        if (currentEnv === COMPLETE_ENV) {
            $('#' + id + '_tr').remove();
        } else {
            let pId = `${id.toString()}_p`;
            let iId = `${id.toString()}_i`;

            $('#' + pId).removeClass('complete');
            $('#' + iId).text('radio_button_unchecked');
        }

        increaseLeftItem();
        updateStatus(id);
    }

    function delTodo(id) {
        $('#' + id + '_tr').remove();
        if (isActive(id)) {
            decreaseLeftItems();
        }

        let todo = getItemFromTodoList(id);
        delCompleteItemsLocal([todo]);
        delCompleteItemsServer([todo]);
        updateCompleteBtn();
    }

    function isActive(id) {
        let todo = getItemFromTodoList(id);
        return todo.status === 0;
    }

    function getItemFromTodoList(id) {
        let todo = todoListLocal.filter(item => item.id === id);
        if (todo.length !== 1) {
            throw new Error('Multi items with same id or no such item');
        }
        return todo[0];
    }

    function updateStatus(id) {
        let todo = getItemFromTodoList(id);
        let index = todoListLocal.indexOf(todo);
        let status = (todoListLocal[index].status + 1) % 2;
        todoListLocal[index].status = status;

        updateStatusServer(id, status);

        updateCompleteBtn();
    }

    function updateCompleteBtn() {
        if (getCompleteItems(todoListLocal).length === 0) {
            clearCompleteBtn.css('display', 'none');
        } else {
            clearCompleteBtn.css('display', 'block');
        }
    }

    function resetTable(todoList) {
        todoTable.empty();
        todoTable.append('<tbody></tbody>');
        for (let todo of todoList) {
            addTodoToTable(todo.id, todo.content, todo.status);
        }
    }

    function addTodoToTable(id, content, status) {
        let tr = createTodoDom(id, content, status);
        todoTable.append(tr);

        $('#' + id.toString() + '_tr').click(function () {
            // 添加item的点击监听
            if (isComplete(id)) {
                return active(id);
            }
            return complete(id);
        });

        // 添加删除按钮的点击监听
        $('#' + id.toString() + '_del_btn').click(function () {
            return delTodo(id);
        });
    }

    function delCompleteItemsServer(completeItems) {
        completeItems = completeItems.map(item => item.id);
        let request = $.ajax({
            url: `${HOST}:${PORT}/todo`,
            method: 'DELETE',
            data: JSON.stringify(completeItems),
            dataType: 'json'
        });

        request.done(function (msg) {
            if (msg.result === SUCCESS) {
                msgDiv.text('[删除]同步成功');
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
            } else {
                msgDiv.text('[删除]同步失败，重新同步中，请稍等……');
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
                setTimeout(() => {
                    delCompleteItemsServer(completeItems);
                }, 10000);
            }
        });

        request.fail(function (jqXHR, textStatus) {
            console.log(jqXHR);
            console.log(textStatus);
            msgDiv.text(`网络异常，[删除]同步失败，重新同步中，请稍等……`);
            msgDiv.css('visibility', 'visible');
            setTimeout(() => {
                msgDiv.css('visibility', 'hidden');
            }, 1000);
            setTimeout(() => {
                delCompleteItemsServer(completeItems);
            }, 10000);
        });
    }

    function getTodoItemsFromServer() {
        let request = $.ajax({
            url: `${HOST}:${PORT}/todo`,
            method: 'GET'
        });

        request.done(function (msg) {
            msg = JSON.parse(msg);
            if (msg.result === SUCCESS) {
                todoListLocal = msg.message;
                todoListLocal.forEach(item => {
                    item.id = parseInt(item.id);
                    item.status = parseInt(item.status);
                });
                // console.log(todoListLocal);
                msgDiv.text('同步成功');
                initView();
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
            } else {
                msgDiv.text('同步失败，请刷新重试');
                msgDiv.css('visibility', 'visible');
            }
        });

        request.fail(function (jqXHR, textStatus) {
            console.log(jqXHR);
            console.log('text status ' + textStatus.message);
            msgDiv.text(`网络异常，同步失败，请刷新重试`);
            msgDiv.css('visibility', 'visible');
        });
    }

    function addTodoToServer(id, content, status) {
        let todo = {'id': id, 'content': content, 'status': status};
        let request = $.ajax({
            url: `${HOST}:${PORT}/todo`,
            method: 'POST',
            data: JSON.stringify(todo),
            dataType: 'json'
        });

        request.done(function (msg) {
            if (msg.result === SUCCESS) {
                msgDiv.text('[新增]同步成功');
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
            } else {
                msgDiv.text(`[新增]同步失败，重新同步中，请稍等……`);
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
                setTimeout(() => {
                    addTodoToTable(id, content, status);
                }, 10000);
            }
        });

        request.fail(function (jqXHR, textStatus) {
            console.log(jqXHR);
            console.log('text status ' + textStatus.message);
            msgDiv.text(`网络异常，[新增]同步失败，重新同步中，请稍等……`);
            msgDiv.css('visibility', 'visible');
            setTimeout(() => {
                msgDiv.css('visibility', 'hidden');
            }, 1000);
            setTimeout(() => {
                addTodoToTable(id, content, status);
            }, 10000);
        });
    }

    function updateStatusServer(id, status) {
        let request = $.ajax({
            url: `${HOST}:${PORT}/todo`,
            method: 'PUT',
            data: JSON.stringify({id: id, status: status}),
            dataType: 'json'
        });

        request.done(function (msg) {
            if (msg.result === SUCCESS) {
                msgDiv.text('[修改]同步成功');
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
            } else {
                msgDiv.text('[修改]同步失败，重新同步中，请稍等……');
                msgDiv.css('visibility', 'visible');
                setTimeout(() => {
                    msgDiv.css('visibility', 'hidden');
                }, 1000);
                setTimeout(() => {
                    updateStatusServer(id, status);
                }, 10000);
            }
        });

        request.fail(function (jqXHR, textStatus) {
            console.log(jqXHR);
            console.log(textStatus);
            msgDiv.text(`网络异常，[修改]同步失败，重新同步中，请稍等……`);
            msgDiv.css('visibility', 'visible');
            setTimeout(() => {
                msgDiv.css('visibility', 'hidden');
            }, 1000);
            setTimeout(() => {
                updateStatusServer(id, status);
            }, 10000);
        });
    }
};
